#ifndef IRQ_H
#define IRQ_H

#include "types.h"
#pragma pack(1)
typedef struct _gate_desc_t{
    uint16_t offset_low;
    uint16_t selector;
    uint16_t  attr;
    uint16_t offset_high;
}gate_desc_t;
#pragma pack()

#define INT_GATE_P    (1<<15)
#define INT_GATE_DPL0 (0<<13)
#define INT_GATE_DPL3 (3<<13)
//#define INT_GATE_D    (1<<11) //1=32位,0=16位
#define INT_GATE_TYPE32 (0xE<<8)

typedef struct _exception_frame_t{
    uint32_t gs,fs,es,ds;
    uint32_t edi,esi,ebp,esp,ebx,edx,ecx,eax;
    uint32_t num,error_code;
    uint32_t eip,cs,eflags;
    uint32_t esp3,ss3;//work during privilege change
}exception_frame_t;

void gate_desc_set(gate_desc_t *desc,uint16_t selector,uint32_t offset,uint16_t attr);
void irq_init();

typedef void (*irq_handler_t)(void);
int irq_install(int irq_num,irq_handler_t handler);

void exception_handler_unknown(void);
void exception_handler_divide_error(void);
void exception_handler_debug(void);
void exception_handler_nmi(void);
void exception_handler_breakpoint(void);
void exception_handler_overflow(void);
void exception_handler_bound_range_exceeded(void);
void exception_handler_invalid_opcode(void);
void exception_handler_device_not_available(void);
void exception_handler_double_fault(void);
//void exception_handler_coprocessor_segment_overrun(void);
void exception_handler_invalid_tss(void);
void exception_handler_segment_not_present(void);
void exception_handler_stack_segment_fault(void);
void exception_handler_general_protection_fault(void);
void exception_handler_page_fault(void);

void exception_handler_fpu_fault(void);
void exception_handler_alignment_check(void);
void exception_handler_machine_check(void);
void exception_handler_simd_floating_point(void);
void exception_handler_virtualization(void);
void exception_handler_control_protection(void);

#define IRQ_UNKNOWN      127
#define IRQ0_DE_DIVIDE_ERROR 0
#define IRQ1_DB_DBG          1 //debug exception
#define IRQ2_NMI          2 //non-maskable interrupt
#define IRQ3_BP_BREAKPOINT   3 //breakpoint exception
#define IRQ4_OF_OVERFLOW     4 //into detected overflow
#define IRQ5_BR_BOUND_RANGE       5 //into detected bounds check,BOUND Range Exceeded
#define IRQ6_UD_INVALID_OP   6 //invalid opcode (Undefined Opcode)
#define IRQ7_NM_DEVICE_NOT_AVAILABLE 7 //device not available (No Math Coprocessor)
#define IRQ8_DF_DOUBLE_FAULT 8 //double fault (Double Fault)
//#define IRQ9_COPROC_SEG_OVERRUN 9 //coprocessor segment overrun (reserved)
#define IRQ10_TS_INVALID_TSS 10 //invalid TSS
#define IRQ11_NP_SEG_NOT_PRESENT 11 //segment not present
#define IRQ12_SS_STACK_FAULT 12 //stack segment fault
#define IRQ13_GP_PROTECTION 13 //general protection
#define IRQ14_PF_PAGE_FAULT 14 //page fault

//#define IRQ15_SP_SPURIOUS_INTERRUPT 15 //spurious interrupt
#define IRQ16_MF_MATH_FAULT 16 //math fault
#define IRQ17_AC_ALIGNMENT_CHECK 17 //alignment check
#define IRQ18_MC_MACHINE_CHECK 18 //machine check
#define IRQ19_XM_SIMD_FLOATING_POINT 19 //SIMD floating-point exception
#define IRQ20_VE_VIRTUALIZATION 20 //virtualization exception
#define IRQ21_CP_CONTROL_PROTECTION 21 //control protection exception
//8259A PIC
#define PIC_ICW1_ALWAYS_1 (1<<4) 
#define PIC_ICW1_ICW4 (1<<0)
#define PIC_ICW4_8086 (1<<0)
#define PIC_OCW2_EOI  (1<<5)

#define PIC0_ICW1 0x20
#define PIC0_ICW2 0x21
#define PIC0_ICW3 0x21
#define PIC0_ICW4 0x21
#define PIC0_OCW2 0x20

#define PIC1_ICW1 0xA0
#define PIC1_ICW2 0xA1
#define PIC1_ICW3 0xA1
#define PIC1_ICW4 0xA1
#define PIC1_OCW2 0xA0

#define PIC0_IMR 0x21
#define PIC1_IMR 0xA1

#define IRQ_PIC_START 0x20
#define IRQ32_TIME IRQ_PIC_START
#define IRQ1_KEYBOARD  0x21
#define IRQ14_DISK_PRI 0x2E
#define IRQ15_DISK_SEC 0x2F

#define IRQ12_MOUSE    0x74
//error code general protection
#define ERR_EXT        (1<<0)
#define ERR_IDT        (1<<1)
#define ERR_TI         (1<<2)
//PAGE Fault Exception
#define ERR_PAGE_P        (1<<0)
#define ERR_PAGE_WR       (1<<1)
#define ERR_PAGE_US       (1<<2)

void irq_disable_global();
void irq_enable_global();
void irq_enable(int irq_num);
void irq_disable(int irq_num);
void pic_init(void);
//tell 8259 the intrupt end
void pic_send_eoi(int irq_num);

//about critical zone
typedef uint32_t irq_state_t;
irq_state_t irq_enter_protect(void);
void irq_exit_protect(irq_state_t irq_state);

#endif